/*
 * Copyright 2011 woozzu
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hi.hiparty.ui.widget;

import com.hi.hiparty.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class PullDownRefreshListView extends ListView {

	private View mHeaderContainer = null;
	private View mHeaderView = null;
	private ImageView mArrow = null;
	private ProgressBar mProgress = null;
	private TextView mText = null;
	private float mY = 0;
	private float mHistoricalY = 0;
	private int mHistoricalTop = 0;
	private int mInitialHeight = 0;
	private boolean mFlag = false;
	private boolean mArrowUp = false;
	private boolean mIsRefreshing = false;
	private int mHeaderHeight = 0;
	private OnRefreshListener mListener = null;

	private static final int REFRESH = 0;
	private static final int NORMAL = 1;
	private static final int HEADER_HEIGHT_DP = 62;
	private static final String TAG = PullDownRefreshListView.class.getSimpleName();

	public PullDownRefreshListView(final Context context) {
		super(context);
		initialize();
	}

	public PullDownRefreshListView(final Context context, final AttributeSet attrs) {
		super(context, attrs);
		initialize();
	}

	public PullDownRefreshListView(final Context context, final AttributeSet attrs, final int defStyle) {
		super(context, attrs, defStyle);
		initialize();
	}

	public void setOnRefreshListener(final OnRefreshListener l) {
		mListener = l;
	}

	public void completeRefreshing() {
		mProgress.setVisibility(View.INVISIBLE);
		mArrow.setVisibility(View.VISIBLE);
		mHandler.removeMessages(REFRESH);
		mHandler.removeMessages(NORMAL);
		mHandler.sendMessage(mHandler.obtainMessage(NORMAL, mHeaderHeight, 0));
		mIsRefreshing = false;
		invalidateViews();
	}

	@Override
	public boolean onInterceptTouchEvent(final MotionEvent ev) {
		Log.d(TAG, "onInterceptTouchEvent start");
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG, "onInterceptTouchEvent处理ACTION_DOWN");

			mHandler.removeMessages(REFRESH);
			mHandler.removeMessages(NORMAL);
			mY = mHistoricalY = ev.getY();
			if (mHeaderContainer.getLayoutParams() != null) {
				mInitialHeight = mHeaderContainer.getLayoutParams().height;
				Log.d(TAG, "mInitialHeight = " + mInitialHeight);
			}
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(final MotionEvent ev) {
		Log.d(TAG, "onTouchEvent start");
		switch (ev.getAction()) {
		case MotionEvent.ACTION_MOVE:
			mHistoricalTop = getChildAt(0).getTop();
			Log.d(TAG, "onTouchEvent处理ACTION_MOVE，获取最顶上的一个view的top位置" + mHistoricalTop);
			break;
		case MotionEvent.ACTION_UP:
			if (!mIsRefreshing) {
				if (mArrowUp) {
					Log.d(TAG, "松开时箭头向上，开始刷新");
					startRefreshing();
					mHandler.sendMessage(mHandler.obtainMessage(REFRESH, (int) (ev.getY() - mY) / 2 + mInitialHeight, 0));
				} else {
					Log.d(TAG, "松开时箭头向下，不刷新");
					if (getChildAt(0).getTop() == 0) {
						Log.d(TAG, "已经显示到顶部");
						mHandler.sendMessage(mHandler.obtainMessage(NORMAL,
								(int) (ev.getY() - mY) / 2 + mInitialHeight, 0));
					}
				}
			} else {
				Log.d(TAG, "正在刷新");
				mHandler.sendMessage(mHandler.obtainMessage(REFRESH, (int) (ev.getY() - mY) / 2 + mInitialHeight, 0));
			}
			mFlag = false;
			break;
		}
		return super.onTouchEvent(ev);
	}

	@Override
	public boolean dispatchTouchEvent(final MotionEvent ev) {
		Log.d(TAG, "dispatchTouchEvent start: MotionEvent:" + ev.getAction() + ", getFirstVisiblePosition:"
				+ getFirstVisiblePosition());
		if (ev.getAction() == MotionEvent.ACTION_MOVE && getFirstVisiblePosition() == 0) {

			float direction = ev.getY() - mHistoricalY;
			Log.d(TAG, "dispatchTouchEvent移动方向:" + direction);

			int height = (int) (ev.getY() - mY) / 2 + mInitialHeight;
			if (height < 0) {
				height = 0;
			}
			Log.d(TAG, "height:" + height);

			float deltaY = Math.abs(mY - ev.getY());
			ViewConfiguration config = ViewConfiguration.get(getContext());
			if (deltaY > config.getScaledTouchSlop()) {
				Log.d(TAG, "手指移动的距离:" + deltaY + "px, 超过了设置里最小的距离" + config.getScaledTouchSlop());

				// Scrolling downward
				if (direction > 0) {
					// Refresh bar is extended if top pixel of the first item is
					// visible
					if (getChildAt(0).getTop() == 0) {
						if (mHistoricalTop < 0) {

							// mY = ev.getY(); // TODO works without
							// this?mHistoricalTop = 0;
						}

						// Extends refresh bar
						Log.d(TAG, "且目前已经显示到了第一行，则开始设置头部刷新区域");
						setHeaderHeight(height);

						// Stop list scroll to prevent the list from
						// overscrolling
						ev.setAction(MotionEvent.ACTION_CANCEL);
						mFlag = false;
					}
				} else if (direction < 0) {
					// Scrolling upward

					// Refresh bar is shortened if top pixel of the first item
					// is
					// visible
					if (getChildAt(0).getTop() == 0) {
						Log.d(TAG, "且目前已经显示到了第一行，并且头部已经开始展开");
						setHeaderHeight(height);

						// If scroll reaches top of the list, list scroll is
						// enabled
						if (getChildAt(1) != null && getChildAt(1).getTop() <= 1 && !mFlag) {
							ev.setAction(MotionEvent.ACTION_DOWN);
							mFlag = true;
						}
					}
				}
			}

			mHistoricalY = ev.getY();
		}
		try {
			return super.dispatchTouchEvent(ev);
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public boolean performItemClick(final View view, final int position, final long id) {
		if (position == 0) {
			// This is the refresh header element
			return true;
		} else {
			return super.performItemClick(view, position - 1, id);
		}
	}

	private void initialize() {
		LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		mHeaderContainer = inflater.inflate(R.layout.refreshable_list_header, null);
		mHeaderView = mHeaderContainer.findViewById(R.id.refreshable_list_header);
		mArrow = (ImageView) mHeaderContainer.findViewById(R.id.refreshable_list_arrow);
		mProgress = (ProgressBar) mHeaderContainer.findViewById(R.id.refreshable_list_progress);
		mText = (TextView) mHeaderContainer.findViewById(R.id.refreshable_list_text);
		addHeaderView(mHeaderContainer);

//		mHeaderHeight = (int) (HEADER_HEIGHT_DP * getContext().getResources().getDisplayMetrics().density);
//		setHeaderHeight(mHeaderHeight);
	}

	private void setHeaderHeight(final int height) {
		Log.d(TAG, "setHeaderHeight start" + height);
		if (height <= 1) {
			mHeaderView.setVisibility(View.GONE);
		} else {
			mHeaderView.setVisibility(View.VISIBLE);
		}

		// Extends refresh bar
		LayoutParams lp = (LayoutParams) mHeaderContainer.getLayoutParams();
		if (lp == null) {
			lp = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
		}
		lp.height = height;
		mHeaderContainer.setLayoutParams(lp);

		// Refresh bar shows up from bottom to top
		LinearLayout.LayoutParams headerLp = (LinearLayout.LayoutParams) mHeaderView.getLayoutParams();
		if (headerLp == null) {
			headerLp = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
		}
		headerLp.topMargin = -mHeaderHeight + height;
		mHeaderView.setLayoutParams(headerLp);

		if (!mIsRefreshing) {
			// If scroll reaches the trigger line, start refreshing
			if (height > mHeaderHeight && !mArrowUp) {
				mArrow.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.pulldown_refresh_rotate));
				mText.setText("Release to update");
				rotateArrow();
				mArrowUp = true;
			} else if (height < mHeaderHeight && mArrowUp) {
				mArrow.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.pulldown_refresh_rotate));
				mText.setText("Pull down to update");
				rotateArrow();
				mArrowUp = false;
			}
		}
	}

	private void rotateArrow() {
		Drawable drawable = mArrow.getDrawable();
		Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
				Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		canvas.save();
		canvas.rotate(180.0f, canvas.getWidth() / 2.0f, canvas.getHeight() / 2.0f);
		drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
		drawable.draw(canvas);
		canvas.restore();
		mArrow.setImageBitmap(bitmap);
	}

	private void startRefreshing() {
		mArrow.setVisibility(View.INVISIBLE);
		mProgress.setVisibility(View.VISIBLE);
		mText.setText("Loading...");
		mIsRefreshing = true;

		if (mListener != null) {
			mListener.onRefresh(this);
		}
	}

	private final Handler mHandler = new Handler() {

		@Override
		public void handleMessage(final Message msg) {
			Log.d(TAG, "handleMessage:" + msg.what + ",h:" + msg.arg1);
			super.handleMessage(msg);

			int limit = 0;
			switch (msg.what) {
			case REFRESH:
				limit = mHeaderHeight;
				break;
			case NORMAL:
				limit = 0;
				break;
			}

			// Elastic scrolling
			if (msg.arg1 >= limit) {
				setHeaderHeight(msg.arg1);
				Log.d(TAG, "设置refresh模块高度：" + msg.arg1 + "，需要移动到的位置：" + limit);
				int distance = msg.arg1 - limit;
				if (distance == 0) {

				} else if (distance < 10) {
					Log.d(TAG, "只差10px，直接移动到limit");
					mHandler.sendMessage(mHandler.obtainMessage(msg.what, limit, 0));
				} else {
					int displacement = distance / 3;
					if (displacement == 0 || displacement < 10) {
						displacement = distance;
					}
					Log.d(TAG, "移动距离" + displacement + ",移动到" + (msg.arg1 - displacement));
					mHandler.sendMessage(mHandler.obtainMessage(msg.what, msg.arg1 - displacement, 0));
				}
			}
		}

	};

	public interface OnRefreshListener {
		public void onRefresh(PullDownRefreshListView listView);
	}

}